package com.peng.jackson;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import lombok.AllArgsConstructor;
import lombok.Data;


/**
 * Sample1
 *
 * @author lupeng
 * Created on 2022-04-10
 */
public class JsonSerializeSample {

    private static final Logger logger = LoggerFactory.getLogger(JsonSerializeSample.class);

    @AllArgsConstructor
    public static class ExtendableBean {
        public String name;
        private Map<String, String> properties;

        @JsonAnyGetter
        public Map<String, String> getProperties() {
            return properties;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public void setProperties(Map<String, String> properties) {
            this.properties = properties;
        }
    }

    @Data
    @AllArgsConstructor
    public static class Children {
        private String address;
        private int age;
    }

    @Test
    public void s1() throws JsonProcessingException {
        ExtendableBean bean = new ExtendableBean("lupeng",
                new HashMap<>());
        bean.properties.put("attr1", "val1");
        bean.properties.put("attr2", "val2");

        String json = new ObjectMapper().writeValueAsString(bean);
        System.out.println(json);
        // {"name":"lupeng","attr2":"val2","attr1":"val1"}
    }

    @AllArgsConstructor
    //@JsonPropertyOrder(value = {"name", "id"})
    @JsonPropertyOrder(alphabetic = true)
    // {"name":"aaa","id":111}
    public static class MyBean {
        private int id;
        private String name;

        @JsonGetter(value = "name")
        public String getTheName1() {
            return name;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    @Test
    public void s2() throws JsonProcessingException {
        MyBean bean = new MyBean(111, "aaa");
        String result = new ObjectMapper().writeValueAsString(bean);
        System.out.println(result);
        //{"id":111,"name":"aaa"}
    }

    @Data
    @AllArgsConstructor
    public static class MyBean1 {
        private int id;
        @JsonRawValue
        private String value;
    }

    @Test
    public void s3() throws JsonProcessingException {
        MyBean1 bean1 = new MyBean1(1, "{\"attr\":false}");
        String result = new ObjectMapper().writeValueAsString(bean1);
        System.out.println(result);
        // {"id":1,"value":{"attr":false}}
    }

    @AllArgsConstructor
    public enum TypeEnumWithValue {
        TYPE1(1, "Type A"), TYPE2(2, "Type 2");

        private Integer id;
        private String name;

        @JsonValue
        public String getName() {
            return name;
        }

        //@JsonValue
        //public Integer getId() {
        //    return id;
        //}
    }

    @Test
    public void s4() throws JsonProcessingException {
        TypeEnumWithValue type1 = TypeEnumWithValue.TYPE1;
        System.out.println(new ObjectMapper().writeValueAsString(type1));
        // "Type A"
    }

    @Data
    @AllArgsConstructor
    @JsonRootName(value = "user")
    public static class MyBean2 {
        private int id;
        private String name;
    }

    @Test
    public void s5() throws JsonProcessingException {
        MyBean2 bean2 = new MyBean2(1, "222");
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
        System.out.println(objectMapper.writeValueAsString(bean2));
        // {"user":{"id":1,"name":"222"}}
    }

    @Data
    @AllArgsConstructor
    public static class MyBean3 {
        private int id;
        private String name;
        @JsonSerialize(using = CustomSerialize.class)
        private SuperBean superBean;
    }

    public static class SuperBean {

    }

    public static class CustomSerialize extends StdSerializer<SuperBean> {

        public CustomSerialize() {
            this(null);
        }

        public CustomSerialize(Class<SuperBean> t) {
            super(t);
        }

        @Override
        public void serialize(SuperBean superBean, JsonGenerator jsonGenerator,
                SerializerProvider serializerProvider) throws IOException {
            jsonGenerator.writeString("Im super bean");
        }

    }

    @Test
    public void s6() throws JsonProcessingException {
        MyBean3 bean3 = new MyBean3(1, "33", new SuperBean());
        ObjectMapper objectMapper = new ObjectMapper();
        System.out.println(objectMapper.writeValueAsString(bean3));
        // {"id":1,"name":"33","superBean":"Im super bean"}
    }
}
